// stdafx.cpp : source file that includes just the standard includes
//	UIlib.pch will be the pre-compiled header
//	stdafx.obj will contain the pre-compiled type information

#include "StdAfx.h"
#include <vector>

namespace DuiLib
{
	CommonTreeNode::CommonTreeNode(int dataColumn)
	{
		_parent = nullptr;
		_data.resize(dataColumn);
	}

	CommonTreeNode::~CommonTreeNode()
	{
		for (auto node : children())
		{
			removeChild(node);
		}
	}
		
	bool CommonTreeNode::findData(int index) const
	{
		return index < _data.size();
	}
		
	CVar CommonTreeNode::data(int index) const
	{
		if (index>=_data.size())
		{
			return CVar();
		}

		return _data[index];
	}

	void CommonTreeNode::setData(int index, const CVar& data)
	{
		if (index>=_data.size())
		{
			return;
		}

		_data[index] = data;
	}

	CommonTreeNode* CommonTreeNode::parent() const
	{
		return _parent;
	}

	void CommonTreeNode::setParent(CommonTreeNode* pNode)
	{
		_parent = pNode;
	}

	CommonTreeNode::NodeList& CommonTreeNode::children()
	{
		return _children;
	}

	void CommonTreeNode::addChild(CommonTreeNode* pNode)
	{
		if (!pNode)
		{
			return;
		}

		pNode->setParent(this);

		_children.push_back(pNode);
	}

	void CommonTreeNode::removeChild(CommonTreeNode* pNode)
	{
		if (!pNode)
		{
			return;
		}

		auto it = std::find(_children.begin(), _children.end(), pNode);
		if (it == _children.end())
		{
			return;
		}

		delete pNode;

		_children.erase(it);
	}


	//-----------------------------------------------------------------------------------------

	CCommonTreeModel::CCommonTreeModel(int rows, int cols)
	{
		m_pRootNode = new CommonTreeNode(cols);

		m_ColumnCount = cols;

		initHeadData();

		insertRows(0, rows);
	}

	CCommonTreeModel::~CCommonTreeModel()
	{
		removeAll();
	}

	bool CCommonTreeModel::hasIndex(int row, int col, const CModelIndex& parent) const
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (row<0 || col<0 || !pParentNode)
		{
			return false;
		}

		const CommonTreeNode::NodeList& nodelist = pParentNode->children();
		if (row>=nodelist.size())
		{
			return false;
		}

		CommonTreeNode* pNode = nodelist[row];
		if (!pNode)
		{
			return false;
		}

		return pNode->findData(col);
	}

	CModelIndex CCommonTreeModel::index(int row, int col, const CModelIndex& parent) const
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (row < 0 || col < 0 || !pParentNode)
		{
			return CModelIndex();
		}

		const CommonTreeNode::NodeList& nodelist = pParentNode->children();
		if (row >= nodelist.size())
		{
			return CModelIndex();
		}

		CommonTreeNode* pNode = nodelist[row];
		if (!pNode)
		{
			return CModelIndex();
		}

		return createIndex(row, col, (void*)pNode);
	}

	CModelIndex CCommonTreeModel::sibling(int row, int col, const CModelIndex& idx) const
	{
		CommonTreeNode* pNode = getTreeNode(idx);
		if (!pNode)
		{
			return CModelIndex();
		}

		CommonTreeNode* pParentNode = pNode->parent();
		if (!pParentNode)
		{
			return CModelIndex();
		}

		CommonTreeNode::NodeList childrenList = pParentNode->children();
		if (row >= childrenList.size())
		{
			return CModelIndex();
		}

		CommonTreeNode* rowChild = childrenList[row];
		if (!rowChild)
		{
			return CModelIndex();
		}

		return createIndex(row, col, (void*)rowChild);
	}

	CModelIndex CCommonTreeModel::parent(const CModelIndex& child) const
	{
		CommonTreeNode* pNode = getTreeNode(child);
		if (!pNode)
		{
			return CModelIndex();
		}

		CommonTreeNode* pParentNode = pNode->parent();
		if (!pParentNode)
		{
			return CModelIndex();
		}

		if (pParentNode == m_pRootNode)
		{
			return CModelIndex();
		}

		CommonTreeNode* pGrandNode = pParentNode->parent();
		if (!pGrandNode)
		{
			return CModelIndex();
		}

		int row = -1;
		CommonTreeNode::NodeList nodeList = pGrandNode->children();
		for (int r = 0; r < nodeList.size(); r++)
		{
			if (pParentNode == nodeList[r])
			{
				row = r;
			}
		}

		int col = 0;
		return createIndex(row, col, pParentNode);
	}

	bool CCommonTreeModel::hasChild(const CModelIndex& parent) const
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (!pParentNode)
		{
			return false;
		}

		return pParentNode->children().size() > 0;
	}

	int CCommonTreeModel::rowCount(const CModelIndex& parent) const
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (!pParentNode)
		{
			return 0;
		}

		return (int)pParentNode->children().size();
	}

	int CCommonTreeModel::columnCount(const CModelIndex& parent) const
	{
		return m_ColumnCount;
	}

	CVar CCommonTreeModel::data(const CModelIndex& index) const
	{
		CommonTreeNode* pNode = getTreeNode(index);
		if (!pNode)
		{
			return CVar();
		}

		return pNode->data(index.column());
	}

	bool CCommonTreeModel::setData(const CModelIndex& index, const CVar& var)
	{
		CommonTreeNode* pNode = getTreeNode(index);
		if (!pNode)
		{
			return false;
		}

		CVar old = pNode->data(index.column());
		pNode->setData(index.column(), var);

		dataChanged(index, old, var);
		return true;
	}

	CVar CCommonTreeModel::headerData(int section, Orientation orient) const
	{
		if (section >= m_ColumnCount)
		{
			return CVar();
		}

		return m_HeadData[section];
	}

	bool CCommonTreeModel::setHeaderData(int section, Orientation orient, const CVar& var)
	{
		if (section >= m_ColumnCount)
		{
			return false;
		}

		CVar old = m_HeadData[section];

		m_HeadData[section] = var;

		headerDataChanged(section, orient, old, var);

		return true;
	}

	bool CCommonTreeModel::insertRows(int row, int count, const CModelIndex& parent)
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (!pParentNode)
		{
			return false;
		}

		rowsBeforeInsert(row, count, parent);


		CommonTreeNode::NodeList& nodeList = pParentNode->children();
		for (int i = 0; i < count; i++)
		{
			CommonTreeNode* pNode = new CommonTreeNode(m_ColumnCount);
			if (pNode)
			{
				pNode->setParent(pParentNode);
				nodeList.insert(nodeList.begin() + row, pNode);
			}
		}

		rowsInserted(row, count, parent);
		return true;
	}

	bool CCommonTreeModel::removeRows(int row, int count, const CModelIndex& parent)
	{
		CommonTreeNode* pParentNode = getTreeNode(parent);
		if (!pParentNode)
		{
			return false;
		}

		rowsBeforeRemove(row, count, parent);

		CommonTreeNode::NodeList& nodeList = pParentNode->children();
		if (row + count > nodeList.size())
		{
			return false;
		}

		for (int i = 0; i < count; i++)
		{
			nodeList.erase(nodeList.begin() + row);
		}

		rowsRemoved(row, count, parent);

		return true;
	}

	bool CCommonTreeModel::removeAll()
	{
		if(!m_pRootNode)
		{
			return false;
		}

		int rows = rowCount();

		m_pRootNode->removeChild(m_pRootNode); 

		allRemoved(rows);
		return true;
	}

	void CCommonTreeModel::initHeadData()
	{
		for (int i = 0; i < m_ColumnCount; i++)
		{
			m_HeadData.push_back(CVar());
		}
	}

	CommonTreeNode* CCommonTreeModel::getTreeNode(const CModelIndex& index) const
	{
		if (index == CModelIndex())
		{
			return m_pRootNode;
		}

		CommonTreeNode* pNode = (CommonTreeNode*)index.interPtr();
		return pNode;
	}

	CModelIndex CCommonTreeModel::getIndexByInterPtr(const void* interPtr)
	{
		const CommonTreeNode* pNode = static_cast<const CommonTreeNode*>(interPtr);
		if (!pNode)
		{
			return CModelIndex();
		}

		CommonTreeNode* pParentNode = pNode->parent();
		if (!pParentNode)
		{
			return CModelIndex();
		}

		const CommonTreeNode::NodeList& nodeList = pParentNode->children();
		for (int i=0; i<nodeList.size(); i++)
		{
			if (interPtr==nodeList[i])
			{
				return createIndex(i, 0, interPtr);
			}
		}

		return CModelIndex();
	}

}